/******************************************************************************* 
 * Copyright (C) 2012-2015 Microfountain Technology, Inc. All Rights Reserved. 
 * 
 * Unauthorized copying of this file, via any medium is strictly prohibited.   
 * Proprietary and confidential
 * 
 * Last Modified: 2015-9-17 9:04:57
 ******************************************************************************/
package cn.com.xy.sms.sdk.net;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.TelephonyManager;
import cn.com.xy.sms.sdk.Iservice.OnlineParseInterface;
import cn.com.xy.sms.sdk.Iservice.OnlineUpdateCycleConfigInterface;
import cn.com.xy.sms.sdk.Iservice.XyCallBack;
import cn.com.xy.sms.sdk.constant.Constant;
import cn.com.xy.sms.sdk.dex.DexUtil;
import cn.com.xy.sms.sdk.log.LogManager;
import cn.com.xy.sms.sdk.net.util.ServerUtil;
import cn.com.xy.sms.sdk.net.util.Signaturer;
import cn.com.xy.sms.sdk.util.DuoquUtils;
import cn.com.xy.sms.sdk.util.FileUtils;
import cn.com.xy.sms.sdk.util.KeyManager;
import cn.com.xy.sms.sdk.util.LogSdkDoAction;
import cn.com.xy.sms.sdk.util.StringUtils;
import cn.com.xy.sms.sdk.util.XyUtil;
import cn.com.xy.sms.sdk.util.RecordFunctionUtil;
/* SDK-428 huangzhiqiang 20160530 start */
import cn.com.xy.sms.sdk.db.entity.SysParamEntityManager;
/* SDK-428 huangzhiqiang 20160530 end */
/* SDK-570 huangzhiqiang 20160802 start */
import cn.com.xy.sms.sdk.net.util.AESUtils;
import cn.com.xy.sms.sdk.net.util.RSAUtils;
/* SDK-570 huangzhiqiang 20160802 end */
import cn.com.xy.sms.util.UUIDUtils;

public class BaseHttpRunnable implements Runnable {

    public String url;
    public String content;
    public HttpHeaderDto hhd;
    public XyCallBack callBack;
    public boolean isLogin = false;
    public String cmd;
    public boolean isCompress = false;

    // 设置超时时间
    public static int timeoutConnection = 40000;
    //设置读取超时90秒
    public static int readTimeout = 90000;

    public BaseHttpRunnable(String url, HttpHeaderDto hhd, String content,
            boolean isLogin, XyCallBack callBack) {
        init(url, hhd, content, isLogin, null, callBack, false);
    }

    public BaseHttpRunnable(String url, HttpHeaderDto hhd, String content,
            boolean isLogin, String cmd, XyCallBack callBack) {
        init(url, hhd, content, isLogin, cmd, callBack, false);
    }

    public BaseHttpRunnable(String url, HttpHeaderDto hhd, String content,
            boolean isLogin, String cmd, XyCallBack callBack, boolean isCompress) {
        init(url, hhd, content, isLogin, cmd, callBack, isCompress);
    }

    /**
     * 
     * @param url
     * @param hhd
     * @param content
     * @param isLogin
     * @param cmd
     * @param callBack
     * @param isCompress
     */
    public void init(String url, HttpHeaderDto hhd, String content,
            boolean isLogin, String cmd, XyCallBack callBack, boolean isCompress) {
        this.hhd = hhd;
        this.url = url;
        this.content = content;
        this.callBack = callBack;
        this.isLogin = isLogin;
        this.cmd = cmd;
        this.isCompress = isCompress;
    }

    public HttpURLConnection getHttpURLConnection() {
        HttpURLConnection http = null;
        try {
            KeyManager.initAppKey();

            if (url.startsWith("https") || url.startsWith("HTTPS")) {
                http = HttpConnection.createHttpsURLConnection(url);
            } else {
                URL urls = new URL(url);

                http = (HttpURLConnection) urls.openConnection();

            }
            http.setConnectTimeout(timeoutConnection);// 设置连接超时时间
            http.setReadTimeout(readTimeout);// 设置读取时间超时

            http.setDoInput(true);
            http.setDoOutput(true);
            http.setRequestMethod("POST");
            http.setUseCaches(false);// 请求不使用缓存
            http.setInstanceFollowRedirects(true);
            setHttpHeader(hhd, isLogin, cmd, http);
            if (isCompress) {
                http.addRequestProperty("nz", "1");
            }
            /* SDK-570 huangzhiqiang 20160802 start */
            // 标记为AES加密方式
            http.addRequestProperty("encrypt", "2");
            /* SDK-570 huangzhiqiang 20160802 end */
            return http;
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "BaseHttpRunnable getHttpURLConnection error: ", e);
        }
        return null;
    }

    public void callBack(int status, String responseStr) {
        LogManager.d("HTTP", "STATUS: " + status + " responseStr: "
                + responseStr);
        if (callBack != null) {
            callBack.execute(status, responseStr);
        }
    }
    
    public void callBack(String status, String responseStr) {
        LogManager.d("HTTP",  status,responseStr);
        if (callBack != null) {
            callBack.execute(status, responseStr);
        }
    }

    @Override
    public void run() {
        HttpURLConnection http = null;
        OutputStream out = null;
        InputStream dis = null;
        try {
            http = getHttpURLConnection();
            /*SDK-646 zhaojiangwei 20161122 start */
            if (http==null) {
            	 callBack(NetUtil.HTTP_THROWS_EXCEPTION, "http null"); 
            	 return;
			}
            /*SDK-646 zhaojiangwei 20161122 end */
            http.connect();
            out = http.getOutputStream();
            /*SDK-646 zhaojiangwei 20161122 start */
            if (out==null) {
          	  	callBack(NetUtil.HTTP_THROWS_EXCEPTION, "http out null");
          	  	return ;
			}
            /*SDK-646 zhaojiangwei 20161122 end */
        	 /* SDK-574 huangzhiqiang 20160802 start */
            byte[] key = XyUtil.getXyValue().getBytes();
            byte[] requestByteArray = getRequestByteArray(key);
            /* SDK-574 huangzhiqiang 20160802 end */
            out.write(requestByteArray);
            out.flush();
            int code = http.getResponseCode();
            if (code == HttpURLConnection.HTTP_OK) {
            	dis = http.getInputStream();
                byte[] bt = FileUtils.getInputStream(dis);
                int len = bt.length;
                logNetInfo(content, len);
                if (len > Constant.NET_MAX_SIZE) {
                    callBack(NetUtil.HTTP_PACKAGE_TO_BIG, "len > Constant.NET_MAX_SIZE");
                    return;
                }
                /*SDK-565 zhaojiangwei 20160726 start */
                else if (len == 0) {
                    callBack(NetUtil.HTTP_NO_BODYDATA, "len == 0");
                    return;
                }
                /*SDK-565 zhaojiangwei 20160726 end */

                /* SDK-574 huangzhiqiang 20160802 start */
                bt = getResponseByteArray(bt, key);
                /* SDK-574 huangzhiqiang 20160802 end */
                String response = new String(bt, "UTF-8");
                callBack(0, response);
            } else {
                callBack(NetUtil.HTTP_ACCESS_FALIE, "code=" + code); // 访问失败
            }
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "BaseHttpRunnable http error: ", e);
            if (e.getClass() == java.net.SocketTimeoutException.class) {
                callBack(NetUtil.HTTP_CONN_OUTTIME, e.getMessage());// 连接超时
            } else {
                callBack(NetUtil.HTTP_THROWS_EXCEPTION, e.getMessage()); // 抛出异常
            }
        } finally {
            try {
            	/*SDK-646 zhaojiangwei 20161122 start */
            	if (dis!=null) {
            		dis.close();
				}
            	if (out!=null) {
            		out.close();
				}
            	/*SDK-646 zhaojiangwei 20161122 end */
                if (http != null) {
                    http.disconnect();// 关闭连接
                }
            } catch (Throwable e) {
                LogManager.e(Constant.TAG, "BaseHttpRunnable run error: ", e);
            }
        }
    }

    public void setHttpHeader(HttpHeaderDto hhd, boolean isLogin, String cmd,
            HttpURLConnection http) throws Exception {
        if (http == null) {
            return;
        }
        http.addRequestProperty("Content-Type", "text/xml;UTF-8");
        String app_key_sign = Signaturer.sign(
                cn.com.xy.sms.sdk.net.XyHttpRunnable.appKeySign,
                cn.com.xy.sms.sdk.net.XyHttpRunnable.appKey);
        http.addRequestProperty("app-key",
                cn.com.xy.sms.sdk.net.XyHttpRunnable.appKey);
        http.addRequestProperty("app-key-sign", app_key_sign);
        http.addRequestProperty("compress", "1");
        http.addRequestProperty("loginid", "");
        http.addRequestProperty("recordState", RecordFunctionUtil.getrecordState());
        http.addRequestProperty("sdkversion", NetUtil.APPVERSION);// 客户端应用版本号
        if (isLogin) {
            String h_token = Signaturer.sign("",
                    cn.com.xy.sms.sdk.net.XyHttpRunnable.appKey);
            http.addRequestProperty("h-token", h_token);
            http.addRequestProperty("command", "0");
        } else {
            http.addRequestProperty("command", "1");
        }
        if (!StringUtils.isNull(cmd)) {
            http.addRequestProperty("cmd", cmd);
        }
        
        /* SDK-452 zhaojiangwei 2016-05-16 start */
        http.addRequestProperty("abi", getDeviceABIS());
        http.addRequestProperty("uiversion", DexUtil.getUIVersion());
        /* SDK-452 zhaojiangwei 2016-05-16 end */
        
        /* SDK-602 zhaojiangwei 2016-09-08 start */
        String androidId = UUIDUtils.getAndroidId();
        String psuedoId = UUIDUtils.getUniquePsuedoID();
        String referer = DexUtil.getOnLineConfigureData(OnlineUpdateCycleConfigInterface.CONFIG_URL_REFERER);
        if (StringUtils.isNull(referer)) {
            referer = "bizport.cn/66dc91e8b78b1c284027a3eb1be0a70e";
        }
        http.addRequestProperty("ai", Signaturer.sha256Encode(androidId));
        http.addRequestProperty("ni", Signaturer.sha256Encode(psuedoId));
        http.addRequestProperty("referer",  referer);
        /* SDK-602 zhaojiangwei 2016-09-08 end */
        /*DATA-101 zhaojiangwei 20170309 start */
        http.addRequestProperty("net", String.valueOf(getCurrentNetType()));
        /*DATA-101 zhaojiangwei 20170309 end */
        addHeadSign(http);
    }

    protected void addHeadSign(HttpURLConnection http) {
        try {
            /*SDK-552 hewengao start*/
            http.addRequestProperty("x", ServerUtil.getSha256Xid());
            /*SDK-552 hewengao end*/
            if (DexUtil.isAppChannel(XyHttpRunnable.appKey)) {
                if (url.endsWith(NetUtil.REQ_QUERY_TOEKN + "/")) {
                	/* SDK-671 zhaojiangwei 20161111 start */
                    String rawImei = getDeviceId(false);
                    byte[] key = XyUtil.getXyValue().getBytes();
                    byte[] imeis = AESUtils.encrypt(rawImei.getBytes(), key);
                    String sImei = RSAUtils.parseByte2HexStrCaseSensitive(imeis); 
                    http.addRequestProperty("s", sImei);
                    /* SDK-671 zhaojiangwei 20161111 start */
                } else {
                    /* SDK-428 huangzhiqiang 20160530 start */
                    // 号码识别，无法获取IMEI时使用唯一编码代替，用于计算联盟数据使用优先级
                    String pValue = getDeviceId(true);
                    if (StringUtils.isNull(pValue)) {
                        pValue = SysParamEntityManager.getStringParam(Constant.getContext(), Constant.UNIQUE_CODE);
                        pValue = (pValue == null) ? "" : pValue;
                    }
                    /* SDK-428 huangzhiqiang 20160530 end */
                    http.addRequestProperty("p", pValue);
                }
            }
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "BaseHttpRunnable addHeadSign: ", e);
            /* SDK-584 zhaojiangwei 20160906 start */
            DexUtil.saveExceptionLog(e);
            /* SDK-584 zhaojiangwei 20160906 end */
        }
    }

    static String deviceId = null;

    public static String getDeviceId(boolean md5) {
        try {
            if (deviceId == null) {
                deviceId = ((TelephonyManager) Constant.getContext()
                        .getSystemService(Context.TELEPHONY_SERVICE))
                        .getDeviceId();
            }
            if (StringUtils.isNull(deviceId)) {
                return "";
            }
            if (md5) {
                // return StringUtils.getMD5(deviceId);
                // return Signaturer.sign(Signaturer.PRIVKEY, deviceId,
                // "SHA256withRSA");
                return Signaturer.sha256Encode(deviceId);
            } else {
                return deviceId;
            }
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "BaseHttpRunnable getDeviceId: ", e);
        }
        return "";
    }
    
    /*DATA-101 zhaojiangwei 20170309 start */
    protected static boolean isWifiAvailable() {
        boolean opRet = false;
        ConnectivityManager mag = (ConnectivityManager) Constant.getContext()
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = mag.getActiveNetworkInfo();
        if (info != null) {
            if (info.getType() == ConnectivityManager.TYPE_WIFI) {
                opRet = true;
            }
        }
        return opRet;
    }

    protected static int getCurrentNetType() {
        int type = 0;
        if (isWifiAvailable()) {
            type = -1;
        }
        else {
            type = ((TelephonyManager) Constant.getContext().getSystemService(Context.TELEPHONY_SERVICE))
                    .getNetworkType();
        }
        return type;
    }
    /*DATA-101 zhaojiangwei 20170309 end */

    public static void logNetInfo(String req, int length) {
        try {
            LogSdkDoAction logSdkDoAction = DuoquUtils.getLogSdkDoAction();
            if (logSdkDoAction != null) {
                logSdkDoAction.logNetInfo(Constant.TAG, "length=" + length
                        + " req=" + req);
            }
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "BaseHttpRunnable logNetInfo: ", e);
        }
    }
    
    /* SDK-436 zhaojiangwei 2016-05-16 start */
    @SuppressLint("NewApi")
    String getDeviceABIS(){
        String result = "";
        if (Build.VERSION.SDK_INT>=21) {
            String []abis = Build.SUPPORTED_ABIS;
            if (abis.length>=1) {
                result = abis[0];
            }
        }
        else{
            result = Build.CPU_ABI;
        }
        return result;
    }
    /* SDK-436 zhaojiangwei 2016-05-16 end */
    
    /* SDK-574 huangzhiqiang 20160802 start */
    protected byte[] getRequestByteArray(byte[] key) throws Throwable {
        byte[] requestByteArray = content.getBytes("UTF-8");
        if (isCompress) {
            requestByteArray = StringUtils.compressGZip(requestByteArray); // 压缩
        }
        /* SDK-570 huangzhiqiang 20160802 start */
        requestByteArray = AESUtils.encrypt(requestByteArray, key); // 加密
        /* SDK-570 huangzhiqiang 20160802 end */
        return requestByteArray;
    }
 
    protected byte[] getResponseByteArray(byte[] buffer, byte[] key) {
        /* SDK-570 huangzhiqiang 20160802 start */
        byte[] responseByteArray = null;
        /* SDK-620 huangzhiqiang 20160802 start */
        try {
            responseByteArray = AESUtils.decrypt(buffer, key); // 解密
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "BaseHttpRunnable AESUtils.decrypt error", e);
        }
        /* SDK-620 huangzhiqiang 20160802 end */
        /* SDK-570 huangzhiqiang 20160802 end */
        if (isCompress) {
            try {
                responseByteArray = StringUtils.uncompressGZip(responseByteArray == null ? buffer : responseByteArray); // 解压
            } catch (Throwable e) {
                LogManager.e(Constant.TAG, "BaseHttpRunnable uncompressGZip error", e);
            }
        }
        return responseByteArray == null ? buffer: responseByteArray;
    }
    /* SDK-574 huangzhiqiang 20160802 end */
}
